package com.loklok.confuse.util;

import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.LangDataKeys;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiFileFactory;
import com.intellij.psi.PsiManager;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.loklok.confuse.model.CodePathConfig;
import com.loklok.confuse.model.ConfuseConfig;
import com.loklok.confuse.ui.OverwriteFileDialog;
import org.jetbrains.annotations.NotNull;

import javax.swing.*;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;


public class LocalFileUtils {

    // 全局状态，记录用户是否选择“应用于所有文件”
    private static final Map<Project, String> applyToAllMap = new HashMap<>();

    public static PsiDirectory getChildDirNotExistCreate(Project project, VirtualFile root, String childPackage) throws IOException {
        if (root == null || childPackage == null || childPackage == "") {
            return null;
        }
        String[] childs = childPackage.split("\\.");
        VirtualFile childFile = root;
        for (String child : childs) {
            VirtualFile existChildFile = childFile.findChild(child);
            if (existChildFile != null) {
                childFile = existChildFile;
            } else {
                childFile = childFile.createChildDirectory(null, child);
            }
        }

        return PsiManager.getInstance(project).findDirectory(childFile);
    }

    public static void writeFile(AnActionEvent anActionEvent, Project project, String fullPck, String className, String generateCode, FileType fileType) {
        VirtualFile thisVirtualFile = anActionEvent.getData(LangDataKeys.VIRTUAL_FILE);
        VirtualFile contentRoot = ProjectRootManager.getInstance(project).getFileIndex().getContentRootForFile(thisVirtualFile);

        WriteCommandAction.runWriteCommandAction(project, () -> {
            try {
                PsiDirectory directory;
                try {
                    directory = LocalFileUtils.getChildDirNotExistCreate(project,
                            contentRoot, fullPck);
                } catch (IOException ex) {
                    throw new RuntimeException("find or create directory error: ", ex);
                }


                // 检查文件是否已存在
                PsiFile existingFile = directory.findFile(className);

                if (existingFile != null) {
                    // 如果用户已经选择“应用于所有文件”，则直接覆盖
                    if(applyToAllMap.containsKey(project)){
                        String choose = applyToAllMap.get(project);
                        if("Y".equalsIgnoreCase(choose)){
                            existingFile.delete();
                        } else {
                            return;
                        }
                    } else {
                        // 显示自定义对话框
                        OverwriteFileDialog dialog = new OverwriteFileDialog(className);
                        dialog.show();

                        // 处理用户选择
                        if (dialog.getExitCode() == DialogWrapper.OK_EXIT_CODE) {
                            // 覆盖文件
                            existingFile.delete();
                            // 如果用户勾选了“应用于所有文件”，则记录状态
                            if (dialog.isApplyToAll()) {
                                applyToAllMap.put(project, "Y");
                            }
                        } else {
                            // 用户选择“跳过”，跳过当前文件
                            if (dialog.isApplyToAll()) {
                                applyToAllMap.put(project, "N");
                            }
                            return;
                        }
                    }
                }

                PsiFile generateEntityFile = PsiFileFactory.getInstance(project)
                        .createFileFromText(className, fileType, generateCode);

                //格式化代码
                CodeStyleManager.getInstance(project).reformat(generateEntityFile);

                directory.add(generateEntityFile);

            } catch (Exception ex) {
                // 弹框提示
                Messages.showMessageDialog(ex.getMessage(), "error massage:", Messages.getErrorIcon());
            }
        });
    }

    public static void resetApplyToAll(Project project) {
        applyToAllMap.remove(project);
    }

    public static String fileReadString(String readPath){
        try {
            // 文件路径
            Path filePath = Path.of(readPath);
            // 读取文件为字符串
            String content = Files.readString(filePath, StandardCharsets.UTF_8);
            return content;
            // 输出文件内容
        } catch (Exception e) {

        }
        return null;
    }

    public static void backgroundGenerateCode(
            AnActionEvent anActionEvent,
            Project project,
            CodePathConfig config,
            String name,
            List<ConfuseConfig.LoadCodeConfigItem> items
    ) {
        ProgressManager.getInstance().run(new Task.Backgroundable(project, "Generating Files", true) {
            private volatile ExecutorService executor;
            private final List<Future<?>> futures = new ArrayList<>();
            private final AtomicBoolean cancelled = new AtomicBoolean(false);

            {
                setCancelText("Click to cancel");
            }

            @Override
            public void run(@NotNull ProgressIndicator indicator) {
                indicator.setText("Generating files...");
                indicator.setFraction(0.0);

                executor = Executors.newFixedThreadPool(4);
                int totalFiles = items.size();
                CountDownLatch completionLatch = new CountDownLatch(totalFiles);

                // 提交任务
                for (ConfuseConfig.LoadCodeConfigItem item : items) {
                    futures.add(executor.submit(() -> {
                        try {
                            if (cancelled.get()) {
                                return;
                            }

                            VelocityUtils.doGenerateCode(anActionEvent, project, config, name, item);
                        } catch (Exception e) {
                            if (!cancelled.get()) {
                                ApplicationManager.getApplication().invokeLater(() ->
                                        Messages.showErrorDialog(project, e.getMessage(), "Generation Error"));
                            }
                        } finally {
                            completionLatch.countDown();
                            updateProgress(indicator, completionLatch.getCount(), totalFiles);
                        }
                    }));
                }

                try {
                    while (!completionLatch.await(100, TimeUnit.MILLISECONDS)) {
                        if (indicator.isCanceled()) {
                            cancelAllTasks();
                            break;
                        }
                    }
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }

                // 最终处理
                if (!cancelled.get()) {
                    indicator.setFraction(1.0);
                    indicator.setText("Generation complete");
                    LocalFileUtils.resetApplyToAll(project);
                }
                executor.shutdown();
            }

            @Override
            public void onCancel() {
                cancelAllTasks();
            }

            private void cancelAllTasks() {
                cancelled.set(true);
                if (executor != null) {
                    executor.shutdownNow();
                }
                futures.forEach(f -> f.cancel(true));
            }

            private void updateProgress(ProgressIndicator indicator, long remaining, int total) {
                int progress = total - (int) remaining;
                indicator.setFraction((double) progress / total);
                indicator.setText2(String.format("Generated %d of %d files", progress, total));
            }
        });
    }
}
